﻿#include "stdafx.h"
#include "MuEncDec.h"

MuEncDec::MuEncDec()
{
}

MuEncDec::~MuEncDec()
{
}

void MuEncDec::Xor3Byte_fccfab(unsigned char *pData, int nLen)
{
	static unsigned char xor_tab_fccfab[] = { 0xfc, 0xcf, 0xab };
	for (int i = 0; i < nLen; i++) pData[i] ^= xor_tab_fccfab[i % 3];
}

bool MuEncDec::ReadEnc_dat(const char *fileName)
{
	return ReadDatFile(fileName, 0x1112, 1, 1, 0, 1, encBaseDat);
}

bool MuEncDec::ReadDec_dat(const char *fileName)
{
	return ReadDatFile(fileName, 0x1112, 1, 0, 1, 1, decBaseDat);
}

//sub_46a370 pBuf==0时返回需求长度,实际解码时可能小于此值
int MuEncDec::DecodeC3C4(unsigned char *pBuf, unsigned char *pByts, int bytsLen)
{
	int rt = 0;
	int n;
	if (bytsLen == 0) return 0;
	if (pBuf == 0) return (bytsLen + 37) / 38 * 32;
	for (int i = 0; i < bytsLen; i += 38)
	{
		n = Decode38to32(pBuf + rt, pByts + i);
		if (n < 0) break;
		rt += n;
	}
	return rt;
}

//sub_46a300 pBuf==0时返回需求长度
int MuEncDec::EncodeC3C4(unsigned char *pBuf, unsigned char *pByts, int bytsLen)
{
	unsigned char buf32[32];
	int nLen;
	int n = bytsLen;
	nLen = (bytsLen + 31) / 32 * 38;
	if (pBuf == 0 || nLen <= 0) return nLen;
	for (int i = 0, j = 0; i < bytsLen; i += 32, j += 38)
	{
		if (n < 32)
		{
			memcpy(buf32, pByts + i, n);
			Encode32to38(pBuf + j, buf32, n);
		}
		else
		{
			Encode32to38(pBuf + j, pByts + i, 32);
			n -= 32;
		}
	}
	return nLen;
}

void MuEncDec::XorDatFile(FILE *fp, unsigned int *pBuf)
{
	static unsigned int xor_tab_datfile[16] = { 0x3f08a79b, 0xe25cc287, 0x93d27ab9, 0x20dea7bf,
		0x837a9bc7, 0x1ffea89b, 0xe836579c, 0xd89a0924,
		0x9d8a73cf, 0x4dea98ce, 0x4dc9ef0f, 0x2bac890a,
		0xf32afe54, 0xd8902a1e, 0x3fdef8f9, 0x5a827990 };
	size_t rdLen = fread(pBuf, 64, 1, fp);
    //assert(rdLen == 1);
	for (int i = 0; i < 16; i++) pBuf[i] ^= xor_tab_datfile[i];
}

bool MuEncDec::ReadDatFile(const char *fileName, int fileTag, int f0, int f1, int f2, int f3, unsigned int *pBuf)
{
	unsigned short buf[4];
	FILE *fp = fopen(fileName, "rb");
	if (!fp) return false;
	fread(buf, 6, 1, fp);
	if (buf[0] != fileTag || *(int *)(buf + 1) != (f0 + f1 + f2 + f3) * 64 + 6)
	{
		fclose(fp);
		return false;
	}
	if (f0) XorDatFile(fp, pBuf);
	if (f1) XorDatFile(fp, pBuf + 16);
	if (f2) XorDatFile(fp, pBuf + 32);
	if (f3) XorDatFile(fp, pBuf + 48);
	fclose(fp);
	return 1;
}

//sub_46a860
int MuEncDec::ShiftRight3(int i)
{
	return i >> 3;
}

//sub_46a7c0
void MuEncDec::ShiftBytes(unsigned char *pBuf, unsigned int count, int nBit)
{
	int b;

	if (nBit == 0) return;
	if (nBit > 1)
	{
		b = 8 - nBit;
		for (unsigned int i = count - 1; i > 0; i--)
		{
			pBuf[i] = pBuf[i] >> nBit | pBuf[i - 1] << b;
		}
		pBuf[0] >>= nBit;
	}
	else
	{
		nBit = -nBit;
		b = 8 - nBit;
		for (unsigned int i = 0; i < count - 1; i++)
		{
			pBuf[i] = pBuf[i] << nBit | pBuf[i + 1] >> b;
		}
		pBuf[count - 1] <<= nBit;
	}
}

int MuEncDec::sub_46a680(unsigned char *pBuf, int x, unsigned int *pData, int n1, int n2)
{
	int m, n, j;
	unsigned char *pVar_8 = 0;
	unsigned int var_4;
	unsigned int count;
	unsigned char *p = 0;

	var_4 = n1 + n2;
	count = ShiftRight3(var_4 - 1);
	m = ShiftRight3(n1);
	count += 1 - m;
	pVar_8 = new unsigned char[count + 1];
	memset(pVar_8, 0, count + 1);
	memcpy(pVar_8, (unsigned char*)pData + m, count);
	m = var_4 & 7;
	if (m) pVar_8[count - 1] &= 0xff << (8 - m);
	m = n1 & 7;
	n = x & 7;

	ShiftBytes(pVar_8, count, -m);
	ShiftBytes(pVar_8, count + 1, n);
	m = n > m ? count + 1 : count;
	if (m > 0)
	{
		j = ShiftRight3(x);
		p = pBuf + j;
		for (int i = 0; i < m; i++)
		{
			p[i] |= pVar_8[i];
		}
	}
	delete[] pVar_8;
	return x + n2;
}

//sub_46A3F0
void MuEncDec::Encode32to38(unsigned char *outBuf, unsigned char *inData, int realDataLen)
{
	unsigned int buf[16];
	unsigned int tmp;
	unsigned int n = 0;
	unsigned int m;
	unsigned short *pwData = (unsigned short*)inData;

	memset(outBuf, 0, 38);
	for (int i = 0; i < 16; i++)
	{
		tmp = pwData[i] ^ encBaseDat[48 + i];
		tmp ^= n;
		tmp *= encBaseDat[16 + i];
		n = tmp % encBaseDat[i];
		buf[i] = n;
		n &= 0xffff;
	}

	n = (unsigned short)buf[15];
	for (int i = 14; i >= 0; i--)
	{
		tmp = buf[i] ^ encBaseDat[48 + i];
		tmp ^= n;
		n = (unsigned short)buf[i];
		buf[i] = tmp;
	}

	m = 0;
	for (int i = 0; i < 16; i++)
	{
		m = sub_46a680(outBuf, m, buf + i, 0, 0x10);
		m = sub_46a680(outBuf, m, buf + i, 0x16, 2);
	}

	tmp = 0xf8;
	for (int i = 0; i < 32; i++)
	{
		tmp ^= inData[i];
	}
	n = (unsigned char)realDataLen ^ 0x3d;
	n ^= tmp;
	n = (unsigned char)n + (((unsigned char)tmp) << 8);
	sub_46a680(outBuf, m, &n, 0, 0x10);
}

//sub_46A510
int MuEncDec::Decode38to32(unsigned char *outBuf, unsigned char *inData)
{
	unsigned int buf[16];
	unsigned int tmp;
	unsigned int n = 0;
	unsigned int m = 0;
	unsigned char buf2[4];

	memset(outBuf, 0, 32);
	memset(buf, 0, 64);
	for (int i = 0; i < 16; i++)
	{
		sub_46a680((unsigned char*)(buf + i), 0, (unsigned int*)inData, n, 0x10);
		n += 0x10;
		sub_46a680((unsigned char*)(buf + i), 0x16, (unsigned int*)inData, n, 2);
		n += 2;
	}

	m = (unsigned short)buf[15];
	for (int i = 14; i >= 0; i--)
	{
		tmp = decBaseDat[48 + i];
		tmp ^= buf[i];
		tmp ^= m;
		buf[i] = tmp;
		m = (unsigned short)tmp;
	}

	m = 0;
	for (int i = 0; i < 16; i++)
	{
		tmp = decBaseDat[32 + i];
		tmp *= buf[i];
		tmp %= decBaseDat[i];
		tmp ^= decBaseDat[48 + i];
		tmp ^= m;
		m = (unsigned short)buf[i];
		((unsigned short*)outBuf)[i] = tmp;
	}

	*(int*)buf2 = 0;
	sub_46a680(buf2, 0, (unsigned int*)inData, n, 0x10);
	m = buf2[1];
	buf2[0] ^= (unsigned char)m;
	buf2[0] ^= 0x3d;

	tmp = 0xf8;
	for (int i = 0; i < 32; i++)
	{
		tmp ^= outBuf[i];
	}

	return (tmp == m) ? buf2[0] : -1;
}